/*
 * Matt Adams
 * TCSS 558 HW2
 * Fall 2013
 */
package rmi;

import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.SortedSet;

import tools.Log;
import client.SpellingClient;

/**
 * RMI Spelling Client.
 * 
 * @author Matt Adams
 */
public class RMISpellingClient extends SpellingClient {
    
    /**
     * Name of registry service.
     */
    private final String serviceName;
    
    /**
     * RemoteSpelling object.
     */
    private RemoteSpelling remoteObject;
    
    /**
     * Constructs RMISpellingClient object.
     * 
     * @param hostPortWordsArray Listing of host, port, and query words.
     * @param serviceName Service name.
     */
    public RMISpellingClient(final String[] hostPortWordsArray, final String serviceName) {
        super(hostPortWordsArray);
        this.serviceName = serviceName;
    }
    
    /**
     * Starts rmi spelling client.
     */
    public void start() {
        final Registry registry = getRegistry();
        try {
            this.remoteObject = (RemoteSpelling)((Registry)registry).lookup(this.serviceName);
        } catch (AccessException e) {
            Log.err("Exception accessing remote object: " + e);
        } catch (RemoteException e) {
            Log.err("Remote exception constructing remote object: " + e);
        } catch (NotBoundException e) {
            Log.err("Not bound exception constructing remote object: " + e);
        }
        for (int i = 0; i < this.queryWords.size(); i++) {
            Log.out("Querying service for word: " + this.queryWords.get(i));
            queryServer(this.queryWords.get(i));
        }
    }
    
    /**
     * Sends and receives the result of query using the remote spelling object.
     */
    @Override
    protected void send(String word) {
        SortedSet<String> closeWords = null;
        try {
            closeWords = this.remoteObject.check(word);
        } catch (RemoteException e) {
            Log.err("Remote exception when checking if word is in list: " + e);
        }
        if (closeWords != null) {
            this.displayQueryResponse(word, closeWords.size(), closeWords);
        } else {
            this.displayQueryResponse(word, -1, closeWords);
        }
    }
    
    @Override
    protected void receive(String word) {
        //Unused in RMISpellingClient       
    }
    
    /**
     * Gets rmi registry from a host and port.
     * @return Returns rmi registry.
     */
    private Registry getRegistry() {
        Registry registry = null;
        try {
            registry = LocateRegistry.getRegistry(this.host, this.port);
        } catch (RemoteException e) {
            Log.err("Error locating registry at <host><port>: <" + this.host + "><" + this.port + ">: " + e);
        }
        return registry;
    }
    
    /**
     * Main to run client.
     * @param hostPortNameWordsArray Listing of host, port, service name, and query words.
     */
    public static void main(final String[] hostPortNameWordsArray) {
        if (hostPortNameWordsArray.length < 4) {
            Log.err("Usage of RMISpellingClient: <hostname> <port> <service name> <word> [<word> ...]");
        } else {
            final String serviceName = hostPortNameWordsArray[2];
            final String[] hostPortWordsArray = new String[hostPortNameWordsArray.length - 1];
            hostPortWordsArray[0] = hostPortNameWordsArray[0];
            hostPortWordsArray[1] = hostPortNameWordsArray[1];
            for (int i = 3; i < hostPortNameWordsArray.length; i++) {
                hostPortWordsArray[i - 1] = hostPortNameWordsArray[i];
            }
            final RMISpellingClient rmiClient = new RMISpellingClient(hostPortWordsArray, serviceName);
            rmiClient.start();
        }
    }
}
